from dash import Input, Output, State, callback_context,html,ctx
from dash.exceptions import PreventUpdate
import pandas as pd
from sqlalchemy import and_, func, cast, Float
from datetime import datetime
import json

from models import Product, db,Department
from server import server
from modules.equipment.layouts import generate_equipment_detail
from dash import dcc, dash # 确保导入 dash

from urllib.parse import parse_qs

# serverIP = "192.168.0.163"
import socket  # 新增导入
import requests
from io import BytesIO

def get_local_ip():
    try:
        # 创建临时socket获取本机IP
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        return s.getsockname()[0]
    except Exception:
        return '127.0.0.1'  # 回退地址

serverIP = get_local_ip()  # 自动获取IP
print(f"服务运行在： http://{serverIP}/dash/login")

portNO = "80"
def register_callbacks(dash_app):
    """注册设备台账相关的回调函数"""
    # print("register equipment detail callback11111111111111")
    

    # 修改加载筛选下拉框选项的回调函数
    @dash_app.callback(
        [Output('hospital-filter', 'options'),
         Output('equipment-type-filter', 'options'),
         Output('brand-filter', 'options')],
        [Input('init-load-trigger', 'data'),
         Input('filter-button', 'n_clicks'),
         Input('equipment-table', 'page_current')
        ]
    )
    def load_filter_options(init_trigger, filter_click, page_current):
       
 
        with server.app_context():
            try:
                hospitals = db.session.query(Product.org_short_name_c).distinct().all()
                hospital_options = [{'label': h[0], 'value': h[0]} for h in hospitals if h[0]]
                equipment_category = db.session.query(Product.equipment_category).distinct().all()
                category_options = [{'label': c[0], 'value': c[0]} for c in equipment_category if c[0]]
                brands = db.session.query(Product.manufacturer).distinct().all()
                brand_options = [{'label': b[0], 'value': b[0]} for b in brands if b[0]]
                return hospital_options, category_options, brand_options
            except Exception as e:
                print(f"加载筛选选项出错: {str(e)}")
                return [], [], []

    

    # 处理表格数据加载、筛选和分页
    @dash_app.callback(
        [Output('equipment-table', 'data'),
         Output('equipment-table', 'page_count'),
         Output('pagination-info', 'children'),
         Output('auto-select-trigger-store', 'data')], # <-- 新增 Output
        [Input('equipment-table', 'page_current'),
         Input('equipment-table', 'page_size'),
         Input('equipment-table', 'sort_by'),
         Input('filter-button', 'n_clicks'),
         Input('url-org-store', 'data')], # <-- 新增 Input: 监听URL中的org参数变化
        [State('hospital-filter', 'value'),
         State('equipment-type-filter', 'value'),
         State('brand-filter', 'value'),
         State('price-min', 'value'),
         State('price-max', 'value'),
         State('purchase-date-start', 'date'),
         State('purchase-date-end', 'date'),
         State('hospital-dept-filter', 'value'),      # 假如有科室筛选
         State('filter-device-id', 'value'),              # 设备ID输入框
         State('filter-device-name', 'value'),              # 设备名称输入框
        ]
    )
    def update_table(page_current, page_size, sort_by, n_clicks, url_org, # <-- 新增 url_org 参数
                    hospitals, equipment_category, brands, price_min, price_max,
                    purchase_date_start, purchase_date_end,
                    department, device_id, device_name):
        
        # print("department:", department, type(department))
        if page_current is None:
            page_current = 0
        if page_size is None:
            page_size = 300
        page_size = 300
        with server.app_context():
            # 构建查询条件
            conditions = [Product.is_active == True]

            # 优先使用URL中的org参数进行过滤
            if url_org:
                #  print(f"[DEBUG update_table] Filtering by url_org: {url_org}")
                 conditions.append(Product.org_short_name_c == url_org)
            # 如果URL中没有org参数，则使用下拉框的选中值进行过滤
            elif hospitals:
                # print(f"[DEBUG update_table] Filtering by hospital-filter value: {hospitals}")
                if isinstance(hospitals, list):
                    conditions.append(Product.org_short_name_c.in_(hospitals))
                else:
                    conditions.append(Product.org_short_name_c == hospitals)

            # 科室筛选（联动：只显示所选医院下的科室）
            if department:
                
                if isinstance(department, list):
                    conditions.append(Product.department_name.in_(department))
                    # 取出医院名称字符串，避免传递list
                    if isinstance(hospitals, list):
                        hospital_name = hospitals[0] if hospitals else None
                    else:
                        hospital_name = hospitals
                    if hospital_name:
                        depts = db.session.query(Department.dept_name)\
                            .filter(Department.org_name == hospital_name, Department.is_active == True)\
                            .distinct()\
                            .order_by(Department.dept_name)\
                            .all()
                        # print("selected_hospital:", hospital_name)
                        # print("depts:", depts)
                else:
                    conditions.append(Product.department_name == department)
            
            # 设备ID精确查询
            if device_id:
                try:
                    # 确保 device_id 是字符串以便后续处理，即使它是数字也先转字符串
                    device_id_str = str(device_id).strip()
                    if device_id_str: # 确保转换后非空
                        device_id_int = int(device_id_str)
                        conditions.append(Product.id == device_id_int)
                        # print(f"[DEBUG update_table] Applied device_id filter: {device_id_int}")
                except ValueError:
                    print(f"[DEBUG update_table] Invalid device_id format, cannot convert to int: {device_id}")
                except Exception as e:
                    print(f"[DEBUG update_table] Error processing device_id {device_id}: {e}")
                    pass  # 非法ID忽略
            
            # 设备名称模糊查询
            if device_name:
                conditions.append(Product.product_name.like(f"%{device_name}%"))
            
            # 设备类型筛选
            if equipment_category:
                if isinstance(equipment_category, list):
                    conditions.append(Product.equipment_category.in_(equipment_category))
                else:
                    conditions.append(Product.equipment_category == equipment_category)
            
            # 品牌筛选
            if brands:
                if isinstance(brands, list):
                    conditions.append(Product.manufacturer.in_(brands))
                else:
                    conditions.append(Product.manufacturer == brands)
            
            # 价格范围筛选
            if price_min is not None and price_min != '':
                conditions.append(cast(Product.price, Float) >= float(price_min))
            if price_max is not None and price_max != '':
                conditions.append(cast(Product.price, Float) < float(price_max))
            
            # 购买日期筛选
            if purchase_date_start:
                start_date = datetime.strptime(purchase_date_start, '%Y-%m-%d')
                conditions.append(Product.purchase_date >= start_date)
            if purchase_date_end:
                end_date = datetime.strptime(purchase_date_end, '%Y-%m-%d')
                conditions.append(Product.purchase_date <= end_date)
            
            # print(f"p150[查询条件] conditions: {db.session.query.statement.compile(compile_kwargs={"literal_binds": True})} ")
            from sqlalchemy.dialects import mysql
            # for cond in conditions:
            #     print(cond.compile(dialect=mysql.dialect(), compile_kwargs={"literal_binds": True}))
            # 计算总记录数
            total_records = db.session.query(func.count(Product.id)).filter(and_(*conditions)).scalar()
            
            # 计算总页数
            if total_records == 0:
                total_pages = 0
            else:
                total_pages = (total_records - 1) // page_size + 1
            
            # 构建排序条件
            order_by = []
            if sort_by:
                for sort in sort_by:
                    col_name = sort['column_id']
                    direction = sort['direction']
                    
                    # 添加字段映射，将表格列ID映射到数据库字段名
                    field_mapping = {
                        'product_id': 'id',
                        'name': 'product_name',
                        'category': 'equipment_category',
                        'brand': 'manufacturer',
                        'model': 'model',
                        'org_name': 'org_short_name_c',
                        'department': 'department_name',  # 添加科室字段映射
                        'purchase_date': 'purchase_date',
                        'price': 'price',
                        'status': 'running_status'
                    }
                    
                    # 使用映射获取正确的字段名
                    if col_name in field_mapping:
                        db_field_name = field_mapping[col_name]
                        col = getattr(Product, db_field_name)
                        if direction == 'asc':
                            order_by.append(col.asc())
                        else:
                            order_by.append(col.desc())
            
            # 如果没有指定排序，默认按ID排序
            if not order_by:
                order_by = [Product.id.desc()]
            
            # 查询数据
            query = db.session.query(
                Product.id,
                Product.product_name,
                Product.equipment_category,
                Product.manufacturer,
                Product.model,
                Product.org_short_name_c,
                Product.department_name,  # 添加科室字段
                Product.purchase_date,
                Product.price,
                Product.running_status
            ).filter(and_(*conditions)).order_by(*order_by)
            
            # 分页
            query = query.offset(page_current * page_size).limit(page_size)
            
            # 执行查询
            results = query.all()
            
            # 运行状态编码到中文的映射
            status_map = {
                '0': '正常运行',
                '1': '故障中',
                '2': '停用中',
                '3': '已报废'
            }

            # 转换为字典列表
            data = []
            for row in results:
                # 获取运行状态，并转换为字符串以便查找映射
                running_status_code = str(row.running_status) if row.running_status is not None else None
                # 根据编码获取中文状态，如果找不到则显示原始编码或'未知状态'
                running_status_chinese = status_map.get(running_status_code, running_status_code if running_status_code is not None else '未知状态')

                item = {
                    'id': row.id,
                    'name': row.product_name,
                    'category': row.equipment_category,
                    'brand': row.manufacturer,
                    'model': row.model,
                    'org_name': row.org_short_name_c,
                    'department': row.department_name,
                    'purchase_date': row.purchase_date.strftime('%Y-%m-%d') if row.purchase_date else '',
                    'price': row.price,
                    'status': running_status_chinese # 使用转换后的中文状态
                }
                data.append(item)

            # 分页信息
            pagination_info = f"显示 {page_current * page_size + 1} 到 {min((page_current + 1) * page_size, total_records)} 条，共 {total_records} 条记录"

            # 返回数据、总页数、分页信息和自动选择触发器数据
            # print(f"[DEBUG update_table] Returning {len(data)} rows.")
            # print(f"[DEBUG update_table] Total pages: {total_pages}")
            # print(f"[DEBUG update_table] Pagination info: {pagination_info}")

            # 检查是否需要触发自动选择第一行
            trigger_auto_select = None
            if len(data) > 0:
                trigger_auto_select = {'row_index': 0}
            return data, total_pages, pagination_info, trigger_auto_select
    
    
    
    # # 新增：处理设备详细信息展示
    # @dash_app.callback(
    #     Output('equipment-details', 'children'),
    #     [Input('equipment-table', 'selected_rows')],
    #     [State('equipment-table', 'data')]
    # )
    # def display_equipment_details(selected_rows, table_data):
    #     if not selected_rows or not table_data:
    #         return html.H4("请在左侧列表中选择一个设备查看详细信息", className="text-center text-muted mt-5")
        
    #     selected_row_index = selected_rows[0]
    #     selected_equipment = table_data[selected_row_index]
    #     # 打印调试信息
    #     # print(f"选中的设备数据: {selected_equipment}")
    #     product_id = selected_equipment.get('id')
    #     if not product_id:
    #         print(f"无法获取产品ID，可用的字段: {list(selected_equipment.keys())}")
    #         return html.H4("无法获取设备ID信息", className="text-center text-muted mt-5")
        
    #     with server.app_context():
    #         # 查询完整的设备信息
    #         equipment = db.session.query(Product).filter(Product.id == product_id).first()
            
    #         if not equipment:
    #             return html.H4("未找到设备信息", className="text-center text-muted mt-5")
            
    #         # 将设备信息转换为字典
    #         equipment_data = {
    #             'product_id': equipment.id,
    #             'product_code': equipment.product_code,
    #             'name': equipment.product_name,
    #             'category': equipment.equipment_category,
    #             'type': equipment.equipment_type,
    #             'brand': equipment.manufacturer,
    #             'model': equipment.model,
    #             'org_name': equipment.org_short_name_c,
    #             'purchase_date': equipment.purchase_date.strftime('%Y-%m-%d') if equipment.purchase_date else '无',
    #             'price': equipment.price,
    #             'status': equipment.running_status,
    #             'software_version': equipment.software_version,
    #             'hardware_version': equipment.hardware_version,
    #             'network_address': equipment.network_address,
    #             'service_life': equipment.service_life,
    #             'technical_parameters': equipment.technical_parameters,
    #             'manufacturer': equipment.manufacturer,
    #             'manufacturer_country': equipment.manufacturer_country,
    #             'production_date': equipment.production_date.strftime('%Y-%m-%d') if equipment.production_date else '无',
    #             'factory_date': equipment.factory_date.strftime('%Y-%m-%d') if equipment.factory_date else '无',
    #             'factory_representative': equipment.factory_representative,
    #             'factory_contact_info': equipment.factory_contact_info,
    #             'running_status': equipment.running_status,
    #             'last_maintenance_date': equipment.last_maintenance_date.strftime('%Y-%m-%d') if equipment.last_maintenance_date else '无',
    #             'next_maintenance_date': equipment.next_maintenance_date.strftime('%Y-%m-%d') if equipment.next_maintenance_date else '无',
    #             'maintenance_count': equipment.maintenance_count,
    #             'fault_count': equipment.fault_count,
    #             'completion_rate': equipment.completion_rate
    #         }
            
    #         # 生成详细信息展示
    #         return generate_equipment_detail(equipment_data)
    
    

    # 新增回调：自动选中表格中的第一行（如果适用）
    @dash_app.callback(
        Output('equipment-table', 'selected_rows'),
        Input('auto-select-trigger-store', 'data'),
        State('equipment-table', 'data'), # 确认表格数据状态
        prevent_initial_call=True
    )
    def auto_select_first_row_in_table(trigger_value, current_table_data):
        # 只要有row_index字段就选中对应行
        if isinstance(trigger_value, dict) and 'row_index' in trigger_value and current_table_data:
            return [trigger_value['row_index']]
        return dash.no_update
    
       
 

    # 回调：点击按钮时，获取当前筛选设备ID，调用接口，弹窗展示二维码
    # 添加客户端回调
    dash_app.clientside_callback(
        """
        function(n_clicks, table_data) {
            if(!n_clicks || !table_data) return;
            var ids = table_data.map(function(row){return row.id;}).join(',');
            window.open('/equipment/generate_qrcodes?device_ids=' + ids, '_blank');
            return;
        }
        """,
        Output('btn-generate-qrcodes', 'n_clicks'),
        Input('btn-generate-qrcodes', 'n_clicks'),
        State('equipment-table', 'data'),
        prevent_initial_call=True
    )
    @dash_app.callback(
        [Output('qr-modal', 'is_open'), Output('qr-content', 'children')],
        [Input('btn-generate-qrcodes', 'n_clicks')],
        [State('hospital-filter', 'value'),
         State('equipment-type-filter', 'value'),
         State('brand-filter', 'value'),
         State('price-min', 'value'),
         State('price-max', 'value'),
         State('purchase-date-start', 'date'),
         State('purchase-date-end', 'date')]
    )
    def show_qrcodes(n_clicks, hospitals, equipment_category, brands, price_min, price_max, purchase_date_start, purchase_date_end):
        if not n_clicks:
            raise PreventUpdate
            
        with server.app_context():
            # 构建基础查询条件
            conditions = [Product.is_active == True]

            # 医院筛选（与导出Excel完全一致）
            if hospitals:
                if isinstance(hospitals, list):
                    conditions.append(Product.org_short_name_c.in_(hospitals))
                else:
                    conditions.append(Product.org_short_name_c == hospitals)

            # 设备类型筛选
            if equipment_category:
                if isinstance(equipment_category, list):
                    conditions.append(Product.equipment_category.in_(equipment_category))
                else:
                    conditions.append(Product.equipment_category == equipment_category)

            # 品牌筛选
            if brands:
                if isinstance(brands, list):
                    conditions.append(Product.manufacturer.in_(brands))
                else:
                    conditions.append(Product.manufacturer == brands)

            # 价格范围筛选
            if price_min not in [None, '']:
                conditions.append(cast(Product.price, Float) >= float(price_min))
            if price_max not in [None, '']:
                conditions.append(cast(Product.price, Float) <= float(price_max))

            # 购买日期筛选
            if purchase_date_start:
                start_date = datetime.strptime(purchase_date_start, '%Y-%m-%d')
                conditions.append(Product.purchase_date >= start_date)
            if purchase_date_end:
                end_date = datetime.strptime(purchase_date_end, '%Y-%m-%d')
                conditions.append(Product.purchase_date <= end_date)

            # 执行查询获取所有符合条件的ID
            query = db.session.query(Product.id).filter(and_(*conditions))
            device_ids = [str(r[0]) for r in query.all()]
            
        import requests
        url = f"http://{serverIP}:{portNO}/equipment/generate_qrcodes"
        print(f"p383 url={url} ")
        resp = requests.post(url, json={"device_ids": device_ids})
        
        # print(f"p385[DEBUG] 请求参数: {device_ids}") 
        # print(resp.text)  # 打印后端返回内容，便于调试
        try:
            qr_imgs = resp.json()
        except Exception as e:
            return False, f"二维码生成接口异常：{str(e)}，返回内容：{resp.text}"
        imgs = [html.Div([
            html.Img(src="data:image/png;base64," + q["qr_img"], style={"width": "120px"}),
            html.Div(f"设备ID: {q['device_id']}")
        ], style={"display": "inline-block", "margin": "10px"}) for q in qr_imgs]
        return True, imgs

    @dash_app.callback(
        Output('export-data', 'data'),
        [Input('export-excel-btn', 'n_clicks'),
        Input('url-org-store', 'data')],
        [State('hospital-filter', 'value'),
        State('equipment-type-filter', 'value'),
        State('brand-filter', 'value'),
        State('price-min', 'value'),
        State('price-max', 'value'),
        State('hospital-dept-filter', 'value'),
        State('equipment-table', 'sort_by')],
        prevent_initial_call=True
    )
    def export_equipment_list(n_clicks, url_org, hospitals, equipment_category, brands, price_min, price_max, department, sort_by):
        # print(f"[DEBUG Export] export_equipment_list triggered. n_clicks: {n_clicks}")
        # print(f"[DEBUG Export] Received states: url_org={url_org}, hospitals={hospitals}, equipment_category={equipment_category}, brands={brands}, price_min={price_min}, price_max={price_max}, department={department}, sort_by={sort_by}")

        if not n_clicks or n_clicks == 0:
            # print("[DEBUG Export] No export button click, preventing update.")
            raise PreventUpdate

        # 初始化查询条件列表
        conditions = [Product.is_active == True]

        # 添加医院筛选条件（根据参数传递方式调整）
        if url_org:
            # print(f"[DEBUG Export] Filtering by url_org: {url_org}")
            conditions.append(Product.org_short_name_c == url_org)
        elif hospitals:
            # print(f"[DEBUG Export] Filtering by hospital-filter value: {hospitals}")
            if isinstance(hospitals, list):
                conditions.append(Product.org_short_name_c.in_(hospitals))
            else:
                conditions.append(Product.org_short_name_c == hospitals)

        # 科室筛选
        if department:
            # print(f"[DEBUG Export] Filtering by department: {department}")
            if isinstance(department, list):
                conditions.append(Product.department_name.in_(department))
            else:
                conditions.append(Product.department_name == department)

        # 设备类型筛选
        if equipment_category:
            # print(f"[DEBUG Export] Filtering by equipment_category: {equipment_category}")
            if isinstance(equipment_category, list):
                conditions.append(Product.equipment_category.in_(equipment_category))
            else:
                conditions.append(Product.equipment_category == equipment_category)

        # 品牌筛选
        if brands:
            # print(f"[DEBUG Export] Filtering by brands: {brands}")
            if isinstance(brands, list):
                conditions.append(Product.manufacturer.in_(brands))
            else:
                conditions.append(Product.manufacturer == brands)

        # 价格区间筛选
        if price_min is not None:
            # print(f"[DEBUG Export] Filtering by price_min: {price_min}")
            conditions.append(Product.price >= price_min)
        if price_max is not None:
            # print(f"[DEBUG Export] Filtering by price_max: {price_max}")
            conditions.append(Product.price <= price_max)

        # 构建排序条件
        order_by = []
        if sort_by:
            # print(f"[DEBUG Export] Applying sort_by: {sort_by}")
            for sort in sort_by:
                col_name = sort['column_id']
                direction = sort['direction']

                # 添加字段映射，将表格列ID映射到数据库字段名
                field_mapping = {
                    'id': 'id', # 确保id也在映射中
                    'name': 'product_name',
                    'category': 'equipment_category',
                    'brand': 'manufacturer',
                    'model': 'model',
                    'org_name': 'org_short_name_c',
                    'department': 'department_name',
                    'purchase_date': 'purchase_date',
                    'price': 'price',
                    'status': 'running_status'
                }

                # 使用映射获取正确的字段名
                if col_name in field_mapping:
                    db_field_name = field_mapping[col_name]
                    col = getattr(Product, db_field_name)
                    if direction == 'asc':
                        order_by.append(col.asc())
                    else:
                        order_by.append(col.desc())
                else:
                    print(f"[DEBUG Export] Warning: Unknown column_id for sorting: {col_name}")


        # 如果没有指定排序，默认按ID排序
        if not order_by:
            order_by = [Product.id.desc()]
            # print("[DEBUG Export] No sort_by specified, defaulting to Product.id.desc()")

        # print(f"[DEBUG Export] Final conditions: {conditions}")
        # print(f"[DEBUG Export] Final order_by: {order_by}")

        with server.app_context():
            # 移除分页参数，查询全部数据
            query = db.session.query(
                Product.id,
                Product.product_code, # 添加产品编码
                Product.product_name,
                Product.equipment_category,
                Product.equipment_type, # 添加设备类型
                Product.manufacturer,
                Product.model,
                Product.org_short_name_c,
                Product.department_name,
                Product.purchase_date,
                Product.price,
                Product.running_status,
                Product.software_version, # 添加软件版本
                Product.hardware_version, # 添加硬件版本
                Product.network_address, # 添加网络地址
                Product.service_life, # 添加使用年限
                Product.technical_parameters, # 添加技术参数
                Product.manufacturer_country, # 添加制造商国家
                Product.production_date, # 添加生产日期
                Product.factory_date, # 添加出厂日期
                Product.factory_representative, # 添加厂家代表
                Product.factory_contact_info, # 添加厂家联系方式
                Product.last_maintenance_date, # 添加上次维保日期
                Product.next_maintenance_date, # 添加下次维保日期
                Product.maintenance_count, # 添加维保次数
                Product.fault_count, # 添加故障次数
                Product.completion_rate # 添加完好率
            ).filter(and_(*conditions)).order_by(*order_by)

            # print(f"[DEBUG Export] Executing query: {query}")
            results = query.all()
            # print(f"[DEBUG Export] Query returned {len(results)} rows.")

            # 转换为DataFrame
            df = pd.DataFrame([{
                'ID': row.id,
                '产品编码': row.product_code,
                '设备名称': row.product_name,
                '设备分类': row.equipment_category,
                '设备类型': row.equipment_type,
                '品牌': row.manufacturer,
                '型号': row.model,
                '所属机构': row.org_short_name_c,
                '科室': row.department_name,
                '购买日期': row.purchase_date.strftime('%Y-%m-%d') if row.purchase_date else '',
                '价格': row.price,
                '运行状态': row.running_status,
                '软件版本': row.software_version,
                '硬件版本': row.hardware_version,
                '网络地址': row.network_address,
                '使用年限': row.service_life,
                '技术参数': row.technical_parameters,
                '制造商国家': row.manufacturer_country,
                '生产日期': row.production_date.strftime('%Y-%m-%d') if row.production_date else '',
                '出厂日期': row.factory_date.strftime('%Y-%m-%d') if row.factory_date else '',
                '厂家代表': row.factory_representative,
                '厂家联系方式': row.factory_contact_info,
                '上次维保日期': row.last_maintenance_date.strftime('%Y-%m-%d') if row.last_maintenance_date else '',
                '下次维保日期': row.next_maintenance_date.strftime('%Y-%m-%d') if row.next_maintenance_date else '',
                '维保次数': row.maintenance_count,
                '故障次数': row.fault_count,
                '完好率': row.completion_rate
            } for row in results])

            # print(f"[DEBUG Export] DataFrame created with {len(df)} rows.")

            # 生成Excel文件
            output = BytesIO()
            try:
                with pd.ExcelWriter(output, engine='openpyxl') as writer:
                    df.to_excel(writer, index=False, sheet_name='设备清单')
                    # 尝试删除默认sheet，如果存在的话
                    if 'Sheet' in writer.book.sheetnames:
                        writer.book.remove(writer.book['Sheet'])
                # print("[DEBUG Export] Excel file generated successfully.")
            except Exception as e:
                print(f"[DEBUG Export] Error generating Excel file: {e}")
                # 返回一个空的下载数据，避免错误
                return dcc.send_bytes(b'', filename="error.xlsx")


            # 返回文件下载
            output.seek(0) # 将文件指针移到开头
            # print("[DEBUG Export] Returning file for download.")
            return dcc.send_bytes(output.getvalue(), filename=f"设备清单_{datetime.now().strftime('%Y%m%d%H%M%S')}.xlsx")


    # 新增：医院与科室下拉框联动
    @dash_app.callback(
        Output('hospital-dept-filter', 'options'),
        Output('hospital-dept-filter', 'value'),
        Output('hospital-dept-filter', 'disabled'),
        Input('hospital-filter', 'value')
    )
    def update_dept_options(selected_hospital):
        dept_options = [{'label': '全部科室', 'value': ''}]
        is_disabled = True
        if not selected_hospital:
            return dept_options, None, is_disabled  # value返回None，不默认选全部科室
        try:
            with server.app_context():
                
                # 支持单选和多选
                if not isinstance(selected_hospital, list):
                    hospital_names = [selected_hospital]
                else:
                    hospital_names = selected_hospital
                all_depts = set()
                for hospital_name in hospital_names:
                    if hospital_name:
                        depts = db.session.query(Department.dept_name)\
                            .filter(Department.org_name == hospital_name, Department.is_active == True)\
                            .distinct()\
                            .all()
                        all_depts.update([d[0] for d in depts if d[0]])
                dept_options += [{'label': d, 'value': d} for d in sorted(all_depts)]
                is_disabled = False if all_depts else True
        except Exception as e:
            print(f"!!! ERROR in update_dept_options: {e}")
        return dept_options, None, is_disabled  # value返回None，不默认选全部科室

   

    
    
    # 合并：根据URL参数或重置按钮设置机构、设备分类和金额区间筛选器的选中状态
    @dash_app.callback(
        [
            Output('hospital-filter', 'value'),
            Output('equipment-type-filter', 'value'),
            Output('price-min', 'value'),
            Output('price-max', 'value'),
            
        ],
        [
            Input('url-org-store', 'data'),
            Input('url-equipment-category-store', 'data'),
            Input('url-price-range-store', 'data'),
            Input('reset-button', 'n_clicks'),
            Input('hospital-filter', 'options')
        ],
        [
            State('hospital-filter', 'options'),
            
        ],
        prevent_initial_call=False
    )
    def update_filters_from_url(url_org, url_equipment_category, url_price_range, reset_clicks, options_input, hospital_options):
        ctx = callback_context
        # print(f"[DEBUG update_filters_from_url] Triggered by: {ctx.triggered_id}, url_org: {url_org}, url_equipment_category: {url_equipment_category}, url_price_range: {url_price_range}, reset_clicks: {reset_clicks}")

        # 1. 清空按钮，全部返回None
        if ctx.triggered_id == 'reset-button' and reset_clicks:
            # print("[DEBUG update_filters_from_url] Reset triggered, returning None for all outputs.")
            return None, None, None, None  # 移除最后一个返回值

        # 2. 处理org参数
        hospital_value = None
        if url_org and hospital_options:
            valid_options = [opt['value'] for opt in hospital_options]
            if url_org in valid_options:
                hospital_value = url_org

        # 3. 处理设备分类参数
        equipment_category_value = url_equipment_category if url_equipment_category else None

        # 4. 处理价格区间参数
        price_min, price_max = None, None
        if url_price_range:
            # print(f"p886 [DEBUG update_filters_from_url] Processing price range: {url_price_range}")
            import re
            m = re.match(r'(\d+)-(\d+)万', url_price_range)
            if m:
                price_min = int(m.group(1))
                price_max = int(m.group(2))
            # 处理"100万以上"格式
            elif url_price_range == '100万以上':
                price_min = 100
                price_max = None
            
        # 5. 判断是否需要触发筛选 - 移到客户端回调中处理
       
        # print(f"[DEBUG update_filters_from_url] Returning: hospital_value={hospital_value}, equipment_category_value={equipment_category_value}, price_min={price_min}, price_max={price_max}")
        return hospital_value, equipment_category_value, price_min, price_max

    @dash_app.callback(
        [
            Output('url-org-store', 'data'),
            Output('url-equipment-category-store', 'data'),
            Output('url-price-range-store', 'data'),
        ],
        [
            Input('url', 'search'),
            Input('reset-button', 'n_clicks')
        ],
        prevent_initial_call=False
    )
    def parse_or_clear_url_stores(search, reset_clicks):
        ctx = callback_context
        # 如果是清空按钮触发，全部返回None
        if ctx.triggered_id == 'reset-button' and reset_clicks:
            return None, None, None
        # 如果是url变化触发，解析参数
        org_value = None
        equipment_category_value = None
        price_range_value = None
        if search:
            try:
                query_params = parse_qs(search.lstrip('?'))
                org_value = query_params.get('org', [None])[0]
                equipment_category_value = query_params.get('equipment_category', [None])[0]
                price_range_value = query_params.get('price_range', [None])[0]
                import requests
                if org_value:
                    org_value = requests.utils.unquote(org_value)
                if equipment_category_value:
                    equipment_category_value = requests.utils.unquote(equipment_category_value)
                if price_range_value:
                    price_range_value = requests.utils.unquote(price_range_value)
            except Exception as e:
                print(f"[DEBUG parse_or_clear_url_stores] Error parsing URL search: {e}")
        return org_value, equipment_category_value, price_range_value

    # 添加一个客户端回调，当URL参数变化时自动点击筛选按钮
    dash_app.clientside_callback(
        """
        function(url_org, url_equipment_category, url_price_range) {
            console.log('[Clientside DEBUG] URL params changed:', url_org, url_equipment_category, url_price_range);
            
            // 如果有任何一个URL参数非空，就触发筛选
            if (url_org || url_equipment_category || url_price_range) {
                console.log('[Clientside DEBUG] URL params not empty, will trigger filter button click');
                
                // 给足够的延迟，确保筛选条件已经设置好
                setTimeout(function() {
                    var filterBtn = document.getElementById('filter-button');
                    if (filterBtn) {
                        console.log('[Clientside DEBUG] Found filter button, clicking it now');
                        filterBtn.click();
                    } else {
                        console.log('[Clientside DEBUG] Filter button not found');
                    }
                }, 1000);  // 增加延迟到1000ms确保筛选条件已经设置好
            }
            
            return window.dash_clientside.no_update;
        }
        """,
        Output('url-params-trigger', 'data'),  # 这是一个虚拟输出
        [
            Input('url-org-store', 'data'),
            Input('url-equipment-category-store', 'data'),
            Input('url-price-range-store', 'data')
        ]
    )

   
    
 
    